using System;
using System.Data;
using System.Xml;
using System.IO;

namespace FreeFlow.Client
{
	/// <summary>
	/// Abstract base class for any list based data
	/// </summary>
	[Serializable]
	public abstract class List : Refreshable
	{
    /// <summary>
    /// Creates a new <see cref="List"/> instance.
    /// </summary>
    protected List() : base()
    {
      listDataSet = new DataSet();
    }

		private DataSet listDataSet;
    /// <summary>
    /// Gets the DataTable containing the list.
    /// </summary>
		public DataTable ListDataTable
		{
			get
      {
				return listDataSet.Tables[ListDataTableName];
			}
		}

    /// <summary>
    /// The name of the DataTable that contains list data.
    /// </summary>
    public const string ListDataTableName = "Row";

    /// <summary>
    /// Abstract method to return the list type used in requests to the engine.
    /// </summary>
		protected abstract string ListType();


    /// <summary>
    /// Returns any request data required for the engine request for this list.
    /// </summary>
    /// <returns></returns>
		protected virtual string RequestData()
		{
			return "";
		}
		
		private string data;
    /// <summary>
    /// Gets the list data returned from the engine.
    /// </summary>
		public string Data
		{
			get {	return data; }
		}

    /// <summary>
    /// Refreshes the items in the list.
    /// </summary>
		public override void RefreshItems()
		{
      CheckConnection();
			
      XmlDocument XMLReq = new XmlDocument();
      XmlElement docElem = XMLReq.CreateElement("eListRequest");
      docElem.InnerXml = RequestData();
      docElem.SetAttribute("List", ListType());

      // order clause
      if ((order != null) && (order.Length > 0))
        docElem.SetAttribute("Order", order);

      // page size
      if (pageSize > 0)
        docElem.SetAttribute("PageSize", pageSize.ToString());

      // page
      if (page > 0)
        docElem.SetAttribute("Page", page.ToString());

      XMLReq.AppendChild(docElem);
			XmlDocument XMLDoc = Connection.SendDecoratedMsg(XMLReq);
			
      if (XMLDoc.DocumentElement != null)
      {
        recordCount = int.Parse(XMLDoc.DocumentElement.GetAttribute("RecordCount"));
        if (XMLDoc.DocumentElement["xml"] != null)
        {
          data = XMLDoc.DocumentElement["xml"].OuterXml;

          using (StringReader Reader = new StringReader(data))
          {
            using (XmlTextReader XMLReader = new XmlTextReader(Reader))
            {
              listDataSet.ReadXml(XMLReader);
            }
          }
        }
      }
		}

    private string filter = string.Empty;
    /// <summary>
    /// Gets or sets a SQL WHERE clause that will be used to filter the list data.
    /// For an alerts list, the filter will be applied to the eAlert table.
    /// For a blank forms list, the filter will be applied to the eStart table. 
    /// An example filter is 
    /// <code>
    /// [C#]
    /// list.Filter = "eMapName = 'My process'";
    /// </code>
    /// </summary>
    public string Filter
    {
      get { return filter; }
      set { filter = value; }
    }

    private string order = string.Empty;
    /// <summary>
    /// Gets or sets a SQL ORDER BY clause that will be used to sort the list data.
    /// An example order clause to get the latest alerts first for an alerts list is 
    /// <code>
    /// [C#]
    /// list.Order = "eUpdated DESC";
    /// </code>
    /// </summary>
    public string Order
    {
      get
      {
        return order;
      }
      set
      {
        order = value;
      }
    }

    private int pageSize;
    /// <summary>
    /// Gets or sets the number of list items to return in the list response.
    /// </summary>
    public int PageSize
    {
      get
      {
        return pageSize;
      }
      set
      {
        pageSize = value;
      }
    }

    private int page;
    /// <summary>
    /// Gets or sets the page to be returned. Numbering starts from 1.
    /// </summary>
    public int Page
    {
      get
      {
        return page;
      }
      set
      {
        page = value;
      }
    }

    private int recordCount;
    /// <summary>
    /// After a call to <see cref="RefreshItems"/>, this will get the total number of records available. 
    /// If paging is being used, this may not equal the number of returned items in the list. 
    /// </summary>
    public int RecordCount
    {
      get
      {
        return recordCount;
      }
    }
	}
}
